package com.example.assetmanagement.service.impl;

import com.example.assetmanagement.common.PageRequest;
import com.example.assetmanagement.common.PageResponse;
import com.example.assetmanagement.domain.Asset;
import com.example.assetmanagement.domain.AssetHistory;
import com.example.assetmanagement.mapper.AssetHistoryMapper;
import com.example.assetmanagement.mapper.AssetMapper;
import com.example.assetmanagement.service.AssetService;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class AssetServiceImpl implements AssetService {

    private final AssetMapper assetMapper;
    private final AssetHistoryMapper historyMapper;

    @Override
    public PageResponse<Asset> list(PageRequest pageRequest, String name, Long categoryId, Integer status) {
        List<Asset> list = assetMapper.selectPage(pageRequest.getOffset(), pageRequest.getSize(), name, categoryId, status);
        long total = assetMapper.count(name, categoryId, status);
        return new PageResponse<>(total, list);
    }

    @Override
    public Asset getById(Long id) {
        return assetMapper.selectById(id);
    }

    @Override
    @Transactional
    public void add(Asset asset) {
        assetMapper.insert(asset);
    }

    @Override
    @Transactional
    public void update(Long id, Asset asset) {
        asset.setId(id);
        assetMapper.update(asset);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        assetMapper.deleteById(id);
    }

    @Override
    @Transactional
    public void batchDelete(List<Long> ids) {
        if (ids == null || ids.isEmpty()) return;
        assetMapper.deleteBatch(ids);
    }

    @Override
    @Transactional
    public void importAssets(MultipartFile file) throws IOException {
        try (Workbook workbook = new XSSFWorkbook(file.getInputStream())) {
            Sheet sheet = workbook.getSheetAt(0);
            for (int i = 1; i <= sheet.getLastRowNum(); i++) { // skip header
                Row row = sheet.getRow(i);
                if (row == null) continue;
                Asset asset = new Asset();
                asset.setCode(getStringCell(row.getCell(0)));
                asset.setName(getStringCell(row.getCell(1)));
                asset.setCategoryId(parseLong(row.getCell(2)));
                asset.setPurchaseDate(parseLocalDate(row.getCell(3)));
                asset.setValue(parseDecimal(row.getCell(4)));
                asset.setStatus(parseInteger(row.getCell(5)));
                asset.setLocation(getStringCell(row.getCell(6)));
                asset.setDescription(getStringCell(row.getCell(7)));
                assetMapper.insert(asset);
            }
        }
    }

    private String getStringCell(Cell cell) {
        return cell == null ? null : cell.getStringCellValue();
    }

    private Long parseLong(Cell cell) {
        if (cell == null) return null;
        switch (cell.getCellType()) {
            case NUMERIC:
                return (long) cell.getNumericCellValue();
            case STRING:
                return Long.parseLong(cell.getStringCellValue());
            default:
                return null;
        }
    }

    private Integer parseInteger(Cell cell) {
        Long l = parseLong(cell);
        return l == null ? null : l.intValue();
    }

    private BigDecimal parseDecimal(Cell cell) {
        if (cell == null) return null;
        switch (cell.getCellType()) {
            case NUMERIC:
                return BigDecimal.valueOf(cell.getNumericCellValue());
            case STRING:
                try {
                    return new BigDecimal(cell.getStringCellValue());
                } catch (NumberFormatException e) {
                    return null;
                }
            default:
                return null;
        }
    }

    private LocalDate parseLocalDate(Cell cell) {
        if (cell == null) return null;
        switch (cell.getCellType()) {
            case STRING:
                return LocalDate.parse(cell.getStringCellValue());
            case NUMERIC:
                return cell.getLocalDateTimeCellValue().toLocalDate();
            default:
                return null;
        }
    }

    @Override
    public byte[] exportAssets(String name, Long categoryId, Integer status) throws IOException {
        List<Asset> list = assetMapper.selectPage(0, Integer.MAX_VALUE, name, categoryId, status);
        try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            Sheet sheet = workbook.createSheet("assets");
            int rowIdx = 0;
            Row header = sheet.createRow(rowIdx++);
            String[] headers = {"编码", "名称", "分类ID", "购置日期", "价值", "状态", "位置", "描述"};
            for (int i = 0; i < headers.length; i++) {
                header.createCell(i).setCellValue(headers[i]);
            }
            for (Asset a : list) {
                Row r = sheet.createRow(rowIdx++);
                r.createCell(0).setCellValue(a.getCode());
                r.createCell(1).setCellValue(a.getName());
                if (a.getCategoryId() != null) r.createCell(2).setCellValue(a.getCategoryId());
                if (a.getPurchaseDate() != null) r.createCell(3).setCellValue(a.getPurchaseDate().toString());
                if (a.getValue() != null) r.createCell(4).setCellValue(a.getValue().doubleValue());
                if (a.getStatus() != null) r.createCell(5).setCellValue(a.getStatus());
                r.createCell(6).setCellValue(a.getLocation() == null ? "" : a.getLocation());
                r.createCell(7).setCellValue(a.getDescription() == null ? "" : a.getDescription());
            }
            workbook.write(out);
            return out.toByteArray();
        }
    }

    @Override
    public List<AssetHistory> getHistoryByAsset(Long assetId) {
        return historyMapper.selectByAssetId(assetId);
    }

    @Override
    @Transactional
    public void addHistory(AssetHistory history) {
        historyMapper.insert(history);
    }
} 